Fork me on GitHub

【Java多线程】JUC锁 08. CountDownLatch

CountDownLatch

1. 前言

  • 一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
  • 计数器无法重置

2. 源码解析

2.1 数据结构

CountDownLatch包含Sync对象,Sync继承于AQS,底层使用AQS共享锁实现

2.2 核心方法

  • CountDownLatch()构造方法
1
2
3
4
5
6
7
8
9
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}

//Sync中实现,设置锁状态为count, "锁计数器"
Sync(int count) {
setState(count);
}
  • await()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}

//AQS获取共享锁
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}

//Sync中实现,返回锁计数是否为0
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}

//让当前线程一直等待,直至获取共享锁或中断才返回
private void doAcquireSharedInterruptibly(long arg)
throws InterruptedException {
// 创建"当前线程"的Node节点,且Node中记录的锁是"共享锁"类型;并将该节点添加到CLH队列末尾。
final Node node = addWaiter(Node.SHARED);
boolean failed = true;
try {
for (;;) {
// 获取上一个节点。
// 如果上一节点是CLH队列的表头,则"尝试获取共享锁"。
final Node p = node.predecessor();
if (p == head) {
long r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);
p.next = null; // help GC
failed = false;
return;
}
}
// (上一节点不是CLH队列的表头) 当前线程一直等待,直到获取到共享锁。
// 如果线程在等待过程中被中断过,则再次中断该线程(还原之前的中断状态)。
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
  • countDown()释放锁
1
2
3
4
5
6
7
8
9
10
11
12
public void countDown() {
sync.releaseShared(1);
}

//AQS中实现
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}

3. 参考

http://www.cnblogs.com/skywang12345/p/3533887.html